home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / ARASAN_S.ZIP / MAKEBOOK.CPP < prev    next >
C/C++ Source or Header  |  1994-08-03  |  8KB  |  331 lines

  1. // Copyright 1994 by Jon Dart.  All Rights Reserved.
  2.  
  3. // Stand-alone executable to build the binary opening book from
  4. // a text file.
  5.  
  6. // There are two book files, one for moves by White and one for
  7. // Black.  Each book consists of three portions: a header, a hash
  8. // table, and an array of book entries.
  9.  
  10. // The header is 8 bytes:
  11. // offset
  12. // 0         version number
  13. // 1-2        hash table size
  14. // 3-4        number of book entries
  15. // 5-7        unused
  16.  
  17. // The hash table is an array of unsigned indexes into the book
  18. // entry array.  A hash code for the position modulo the hash table
  19. // size is used to look up in this array the first book entry for the
  20. // position.
  21.  
  22. // The book entries themselves are structures defined in bookentr.h.
  23. // Each one is 8 bytes and contains the full hash code, the move
  24. // index, a weight indicating how often the computer should play the
  25. // move, and an index to the next entry in the hash chain.
  26.  
  27. // Each book is limited to 65536 bytes, enough to hold slightly over
  28. // 8000 moves.
  29.  
  30. #include "board.h"
  31. #include "array.h"
  32. #include "emove.h"
  33. #include "bookentr.h"
  34. // #include "bookwrit.h"
  35. #include "hash.h"
  36. #include "bhash.h"
  37. #include "movegen.h"
  38. #include "notation.h"
  39. #include "types.h"
  40. extern "C"
  41. {
  42. #include <string.h>
  43. #include <ctype.h>
  44. #include <assert.h>
  45. };
  46.  
  47. #include <fstream.h>
  48. #include <iostream.h>
  49.  
  50. const unsigned MAX_MOVES = 8050;
  51. const unsigned HASH_TABLE_SIZE = 511;
  52.  
  53. struct book_info
  54. {
  55.    unsigned next_free;
  56.     Array < unsigned >*hash_table;
  57.     Array < Book_Entry * >*book_moves;
  58. };
  59.  
  60. static book_info book_data[2];
  61.  
  62. const int Entry_Size = sizeof(Book_Entry);
  63. const int Header_Size = 8;
  64. const int Buffer_Size = 4096;
  65. const byte Book_Version = 2;
  66.  
  67. static Boolean
  68. search(const unsigned start, const unsigned move_index,
  69.        const ColorType side,
  70.        const unsigned long hc)
  71. {
  72.    unsigned indx = start;
  73.    byte hibytes[3];
  74.    Book_Entry be(hc, 0, move_index, 0);
  75.    while (indx != INVALID)
  76.    {
  77.       assert(indx < MAX_MOVES);
  78.       Book_Entry *entry = (*(book_data[side].book_moves))[indx];
  79.       if (*entry == be && entry->move_index == move_index)
  80.      return True;
  81.       indx = entry->next;
  82.    }
  83.    return False;
  84. }
  85.  
  86. static void
  87. add_move(const Board & board, int move_index, int recommend)
  88. {
  89.    unsigned probe = (unsigned) (Board_Hash::HashCode2(board) % HASH_TABLE_SIZE);
  90.    unsigned hit = (*(book_data[board.Side()].hash_table))[probe];
  91.    if (hit == INVALID || !search(hit, move_index, board.Side(),
  92.                  board.HashCode()))
  93.    {
  94.       Book_Entry *new_entry = new Book_Entry(board.HashCode(), recommend,
  95.                          move_index, hit);
  96.       assert(new_entry);
  97.       unsigned next = book_data[board.Side()].next_free;
  98.       (*(book_data[board.Side()].book_moves))[next] = new_entry;
  99.       (*(book_data[board.Side()].hash_table))[probe] = next;
  100. #ifdef DEBUG
  101.       cout << "p:" << probe << " h:" << board.HashCode() << " i:"
  102.      << move_index << " f:" << next << endl;
  103. #endif
  104.       book_data[board.Side()].next_free++;
  105.    }
  106. }
  107.  
  108. static void
  109. write_book(const ColorType side)
  110. {
  111.    byte *write_buffer = new byte[Buffer_Size];
  112.    assert(write_buffer);
  113.    static char *Book_File_Name[2] = {"bookb", "bookw"};
  114.    ofstream book_file(Book_File_Name[side],
  115. #ifdef __BORLANDC__
  116.                ios::out | ios::trunc | ios::binary);
  117. #else
  118.                ios::out | ios::trunc);
  119. #endif
  120.    if (!book_file.good())
  121.       return;
  122.  
  123.    // write the header
  124.  
  125.    book_file.put((char)Book_Version);
  126.    unsigned ht_size = HASH_TABLE_SIZE;
  127.    book_file.write((char *) &ht_size, (int) sizeof(unsigned));
  128.    book_file.write((char *) (&(book_data[side].next_free)),
  129.            (int) sizeof(unsigned));
  130.    // pad out the header to 8 bytes:
  131.    char stuff[3] = {'\0', '\0', '\0'};
  132.    book_file.write(stuff, 3);
  133.  
  134.    // write the hash table
  135.  
  136.    for (int i = 0; i < HASH_TABLE_SIZE; i++)
  137.    {
  138.       unsigned ht_entry = (*(book_data[side].hash_table))[i];
  139.       book_file.put((char)(ht_entry % 256));
  140.       book_file.put((char)(ht_entry / 256));
  141.    }
  142.  
  143.    // write the book moves
  144.  
  145.    unsigned index = 0;
  146.    unsigned limit = book_data[side].next_free;
  147.    for (i = 0; i < limit; i++)
  148.    {
  149.       if (index + sizeof(Book_Entry) <= Buffer_Size)
  150.       {
  151.      memcpy(write_buffer + index,
  152.         (*(book_data[side].book_moves))[i], sizeof(Book_Entry));
  153.      index += sizeof(Book_Entry);
  154.       } else
  155.       {
  156.      unsigned to_go = Buffer_Size - index;
  157.      memcpy(write_buffer + index,
  158.         (*(book_data[side].book_moves))[i], to_go);
  159.      book_file.write(write_buffer, Buffer_Size);
  160.      memcpy(write_buffer,
  161.         (*(book_data[side].book_moves))[i] + to_go, sizeof(Book_Entry) - to_go);
  162.      index = sizeof(Book_Entry) - to_go;
  163.       }
  164.    }
  165.    if (index)
  166.       book_file.write(write_buffer, index);
  167.    book_file.close();
  168.    delete[] write_buffer;
  169.  
  170.    cout << book_data[side].next_free << " moves in "
  171.       << side << " book." << endl;
  172. }
  173.  
  174. int
  175. main(int argc, char **argv)
  176. {
  177.    char book_name[128];
  178.    fstream infile;
  179.  
  180.    if (argc < 2)
  181.       strcpy(book_name, "BOOK.TXT");
  182.    else
  183.       strcpy(book_name, argv[1]);
  184.  
  185.    infile.open(book_name, ios::in);
  186.    if (!infile.good())
  187.    {
  188.       cerr << "Can't open book file: " << book_name << endl;
  189.       return -1;
  190.    }
  191.    book_data[White].book_moves = new Array < Book_Entry * >(MAX_MOVES, False);
  192.    book_data[Black].book_moves = new Array < Book_Entry * >(MAX_MOVES, False);
  193.    book_data[White].hash_table = new Array < unsigned >(HASH_TABLE_SIZE, False);
  194.    book_data[Black].hash_table = new Array < unsigned >(HASH_TABLE_SIZE, False);
  195.    book_data[White].next_free = 0;
  196.    book_data[Black].next_free = 0;
  197.  
  198.    char buf[128];
  199.    char movebuf[20];
  200.    unsigned line = 0;
  201.    char *q;
  202.    Board board;
  203.    Board tmpboard;
  204.    int recommend;
  205.    Move moves[Move_Generator::MaxMoves];
  206.    int dots = 0;
  207.  
  208.    for (unsigned i = 0; i < HASH_TABLE_SIZE; i++)
  209.    {
  210.       (*(book_data[White].hash_table))[i] = INVALID;
  211.       (*(book_data[Black].hash_table))[i] = INVALID;
  212.    }
  213.  
  214.    for (i = 0; i < MAX_MOVES; i++)
  215.    {
  216.       (*(book_data[White].book_moves))[i] = NULL;
  217.       (*(book_data[Black].book_moves))[i] = NULL;
  218.    }
  219.  
  220.    while (!infile.eof() && book_data[White].next_free < MAX_MOVES
  221.       && book_data[Black].next_free < MAX_MOVES)
  222.    {
  223.       recommend = 5;
  224.       infile.getline(buf, 128);
  225. #ifdef DEBUG
  226.       cout << buf << endl;
  227. #endif
  228.       line++;
  229.       char *p = buf;
  230.       while (isspace(*p))
  231.      p++;
  232.       switch (*p)
  233.       {
  234.       case '\0':
  235.      continue;
  236.       case ';':
  237.      continue;
  238.       case 'm':
  239.      tmpboard = board;
  240.      continue;
  241.       case 'r':
  242.      board = tmpboard;
  243.      continue;
  244.       case 's':
  245.       case 't':
  246.      break;            // these are obsolete
  247.  
  248.       case '-':
  249.      board.Reset();
  250.      break;
  251.       default:
  252.      {
  253.         while (*p)
  254.         {
  255.            while (isspace(*p))
  256.           p++;
  257.            if (*p == '\0')
  258.               break;
  259.            q = movebuf;
  260.            int count = 0;
  261.            while (!isspace(*p) && *p && count < 19)
  262.            {
  263.           *q++ = *p++;
  264.           ++count;
  265.            }
  266.            *q = '\0';
  267.            Move move = Notation::Value(board, board.Side(), movebuf);
  268.            if (move.IsNull())
  269.            {
  270.           cerr << endl << "Illegal move in file, line " << 
  271.              line << " (" << movebuf << ")" << endl;
  272.           infile.close();
  273.           return -1;
  274.            }
  275.            ExtendedMove emove(board, move);
  276.  
  277.            // check (pseudo) legality:
  278.            Move_Generator mg(board, 0, Move::NullMove());
  279.            int found = 0;
  280.            int move_indx = 0;
  281.  
  282.            int n = mg.Generate_Moves(moves, False, True);
  283.  
  284.            for (int i = 0; i < n; i++)
  285.            {
  286.           if (moves[i] == emove)
  287.           {
  288.              move_indx = i;
  289.              found++;
  290.              break;
  291.           }
  292.            }
  293.            if (!found)
  294.            {
  295.           cerr << endl << "Illegal move in file, line " << line << " ("
  296.              << movebuf << ")" << endl;
  297.           infile.close();
  298.           return -1;
  299.            }
  300.            dots++;
  301.            if (dots % 50 == 0)
  302.           cout << '.';
  303.            if (dots > 3000)
  304.            {
  305.           cout << endl;
  306.           dots = 1;
  307.            }
  308.            while (isspace(*p))
  309.           p++;
  310.            if (*p)
  311.            {
  312.           if ((*p >= '0') && (*p <= '9'))
  313.           {
  314.              recommend = *p - '0';
  315.              p++;
  316.           }
  317.            }
  318.            add_move(board, move_indx, recommend);
  319.            board.MakeMove(emove);
  320.         }
  321.      }
  322.       }
  323.    }
  324.    infile.close();
  325.  
  326.    cout << endl;
  327.    write_book(White);
  328.    write_book(Black);
  329.    return 0;
  330. }
  331.